
 #include "CPU_const.h"
  extern uint Counter;
  extern uint CorrMes; 
  extern uint CorrVr_L; 
  extern uint CorrVr_H; 
  extern uint CorrVs_L; 
  extern uint CorrVs_H; 
  extern uint BAT;
  extern uint EXBAT;
  extern uint GSM_SIM;
  extern uint GSM_SIGN;
  extern uint GSM_READYF;
  extern int ain[AIN_COUNT];
  extern int din[DIN_COUNT];
  extern int alarm[4];
  extern int power;
  extern int energy1;
  extern usht ReadedOpts;
  extern usht ReadedCtrl;
  extern usht ReadedAO1, ReadedAO2;

  
MODBUS::MODBUS(UARTbuf *pUART, char my_id, char object_id)
{ 
  pUx = pUART; myID = my_id; objectID = object_id; multiplicity = 1; Gamma = false; pGOST = NULL;

}




/****************************************************************************************************/
/*               Q U E R Y      C H E C K I N G     O F      I N P U T     D A T A                  */
/****************************************************************************************************/
void MODBUS::check_Query(void)
{ uint end;
//
  posa = IDseek; /*(*pUx).RecieveIndI(&InBgn);*/  InEnd = InBgn = 0;
  while(1)
   {

     
     
     if(InBgn==InEnd) (*pUx).RecieveIndI(&InEnd);
     switch(posa)
      { 
        case(IDseek):  if(findID()) {InID = InBgn; (*pUx).next(&InBgn);}
                     break;
        case(COMask):  InCmnd = (*pUx).RdBufIn(InBgn);
                       switch(InCmnd)
                        {
                          case(R_H_R):
                          case(P_S_R): posa = ENDwait; NofByte = 8; break;
                          case(M_W_R): posa = ENDwait; NofByte = 10; break;
                          case(P_M_R): posa = NoBwait; NofByte = 7; break;
                          default:     posa = IDseek;
                         }
                     break;
        case(COMansw): InCmnd = (*pUx).RdBufIn(InBgn);
                       switch(InCmnd)
                        {
                          case(P_M_R):
                          case(P_S_R): posa = ENDwait; NofByte = 8; break;
                          case(M_W_R): posa = ENDwait; NofByte = 10; break;
                          case(R_H_R): posa = NoBwait; NofByte = 3; break;
                          case(R_H_R|ERRmsk):
                          case(P_S_R|ERRmsk):
                          case(P_M_R|ERRmsk):
                          case(M_W_R|ERRmsk): posa = ENDwait; NofByte = 5; break;
                          default:     posa = IDseek;
                         }
                     break;
        case(NoBwait): if( (*pUx).CountBytes(InID,InEnd)<NofByte )
                         { (*pUx).RecieveIndI(&InEnd); }
                        else
                         {
                           if(InCmnd==P_M_R) NofByte = 9 + (*pUx).RdBufIn((*pUx).shift(InID,6));
                           if(InCmnd==R_H_R) NofByte = 5 + (*pUx).RdBufIn((*pUx).shift(InID,2));  
                           if( (*pUx).CheckSize(NofByte) ) {posa = ENDwait;} else {posa = IDseek;}
                          }
                     break;
        case(ENDwait): if( (*pUx).CountBytes(InID,InEnd)<NofByte )
                         { (*pUx).RecieveIndI(&InEnd); }
                        else
                         {
                           end = (*pUx).shift(InID,NofByte);
                           if( (*pUx).CRC16in(InID,end) )
                            {(*pUx).SendBrdI(InID); posa = QUERYok;}  else  {posa = IDseek;}
                          }
                     break;
       };/*switch(posa)*/

     if(posa==QUERYok)
      { 
        /*Rxd disable mutex ON*/
        /*function working with query*/
        /*Rxd disable mutex OFF ?????????????? may be not hear*/
        
        if(queryID==myID)
         { 
           formAnswer();
           //U0THR = myID;
         }
        else
         {
           InBgn = (*pUx).shift(InBgn,1); // InID
/*           if (OutAdr==1) CorrMes=readShort();
           else if (OutAdr==502) CorrVr_L=readShort();
           else if (OutAdr==503) CorrVr_H=readShort();
           else if (OutAdr==505) CorrVs_L=readShort();
           else if (OutAdr==506) CorrVs_H=readShort();*/
           if (OutAdr==39)
             ReadedCtrl=readShort();           
           if (OutAdr==40)
             ReadedAO1=readShort();           
           if (OutAdr==41)
             ReadedAO2=readShort();           
           if (OutAdr==44)
             ReadedOpts=readShort();           
         }
        
        posa = IDseek;   InBgn = end; (*pUx).ResetBrdI();
      
       }/*if(posa==QUERYok)*/
                              
                              
       vTaskDelay(100);                       
     
                              
    };/*while(1)*/
//
}
/*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
/*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/




/****************************************************************************************************/
/*                                    F O R M       A N S W E R                                     */
/****************************************************************************************************/
void MODBUS::formAnswer(void)
{ uint adr, n_regs, AnswBgn, error, mskOR;
//mutex catch;
  xSemaphoreTake((*pUx).mWrBufOen, portMAX_DELAY);
//address & number of registers form:
  adr = readShort();   n_regs = readShort();
//answer form:
  AnswBgn = (*pUx).GetBrdO();  (*pUx).WrBufOut(myID);
  switch(InCmnd)
   {
     case(R_H_R): n_regs = RegsToBytes(adr,n_regs<<1);/*transform number of regs to number of bytes*/
                  (*pUx).WrBufOut(InCmnd);   (*pUx).WrBufOut(n_regs);
                  error = 0;
                  dataRead(adr,n_regs);
               break;
     case(P_S_R): error = writeSinglReg(adr,n_regs);
               break;
     case(P_M_R): error = writeMultReg(adr,n_regs);
               break;       
     case(M_W_R): mskOR = readShort(); error = writeMaskReg(adr,n_regs,mskOR);
               break;
    }/*switch(InCmnd)*/
//check error:
  if(!error)
    { 
//      (*pUx).WrBufOut(InCmnd); writeShort(adr); writeShort(n_regs);
      if(InCmnd==M_W_R) writeShort(mskOR);
     } 
   else
    { if(error!=No_ERR) {(*pUx).WrBufOut(InCmnd|0x80); (*pUx).WrBufOut(error);}; }
//CRC16 write:
  (*pUx).CRC16out(AnswBgn);
//start send:
  (*pUx).SetBrdOISR();  (*pUx).StartTransmite();   xSemaphoreGive((*pUx).mWrBufOen);
//
}
/*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
/*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/




/****************************************************************************************************/
/*                                    F O R M       A S K                                           */
/****************************************************************************************************/
uint MODBUS::formAsk(char *pData, uint GammaLo, uint GammaHi)
{ uint AskBgn;
//check out command: later bring this part to another function
  switch(OutCmnd)
   {
     case(R_H_R):
     case(P_S_R):
     case(P_M_R):
     case(M_W_R): break;
         default: return ILL_FUNC;
    }/*switch(OutCmnd)*/
//mutex catch:
  xSemaphoreTake((*pUx).mWrBufOen, portMAX_DELAY);
//gamma write
  if(Gamma)
    { writeLong(GammaLo);  writeLong(GammaHi);   (*pGOST).INITgen(&GammaHi,&GammaLo); }
//definition the begin of query in output buffer
  AskBgn = (*pUx).GetBrdO();
//answer form:
  (*pUx).WrBufOut(objectID);  (*pUx).WrBufOut(OutCmnd);  writeShort(OutAdr); 
  switch(OutCmnd)
   {
     case(R_H_R): writeShort(OutNregs); break;
     case(P_S_R): writeShort(OutData1); break;
     case(P_M_R): writeShort(OutNregs); (*pUx).WrBufOut((char)OutNregs<<1);
                  writeData(pData,OutNregs);
              break;       
     case(M_W_R): writeShort(OutData1); writeShort(OutData2); break;
    }/*switch(OutCmnd)*/
//CRC16 write:
  (*pUx).CRC16out(AskBgn);
//encryption
  if(Gamma) XORask(AskBgn);
//start send:
  (*pUx).SetBrdOISR();  (*pUx).StartTransmite();   xSemaphoreGive((*pUx).mWrBufOen);
//
  return No_ERR;
}
/*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
/*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/

void MODBUS::writeData(usht *pData, uint Nregs)
{
  while(Nregs) {writeShort(*pData++); --Nregs;}
 
}

void MODBUS::SetMultiplicity(char val)   { multiplicity = val; }

char MODBUS::GetMultiplicity(void)   { return multiplicity; }

extern int AIN_RES[10];

uint MODBUS::dataRead(uint adr, uint n_bytes)
{ 
  uint reg;
//   uint regZ;
  char i;
//  while(n_bytes) { (*pUx).WrBufOut(0x56+n_bytes); --n_bytes; }
  //  int AIN_TEMP=GET_AIN(2);
  if (adr==6) writeShort(AIN_RES[0]);
  else if (adr==7) writeShort(BAT);
//  else if (adr==8) writeShort(EXBAT);
  else if (adr==9) {
    reg=0;   
 //   writeShort(regZ);
   GET_REG_INFO();
   for (i=0; i<14; i++)     
      if (GET_REG(i)) reg|=(1<<(i));   
     writeShort(reg);
   
     
    
    
    if (GSM_READYF==3) reg|=1<<11;
    if (GSM_READYF==3) reg|=1<<12;
  }
  else if ((adr>=10) && (adr<=20)) writeShort(GET_AIN((adr-10)>>1));
  
  else if (adr==22) writeShort(GSM_SIM);
  else if (adr==23) writeShort(power);
  else if (adr==25) writeShort(energy1);
  else if (adr==29)
  {
    uint regout=0;

     for (i=0; i<5; i++)   
     regout|=(GET_DOUT(i)<<(i));   
     writeShort(regout);
  }
/*  else if (adr==35) writeShort(CorrVr_H);
  else if (adr==36) writeShort(CorrVr_L);
  else if (adr==37) writeShort(CorrVs_H);
  else if (adr==38) writeShort(CorrVs_L);
  else if (adr==45) writeShort(GSM_SIGN);
  else if (adr==46) writeShort(CorrMes);*/
  else writeShort(Counter++);
  if (n_bytes==4) writeShort(Counter++);
  return No_ERR;
}
int GET_POW()
{
  return power;
}

int GET_ENERGY()
{
  return energy1;
}

int GET_CORR1()
{
 /// CorrVr_H=CorrVr_H+CorrVr_L/10000;
  return 0;//CorrVr_H;
}
int GET_CORR2()
{
  ///CorrVs_H=CorrVs_H+CorrVs_L/10000;
  return 0;//CorrVr_L;
}

int GET_CORR1S()
{
  return 0;//CorrVs_H;
}
int GET_CORR2S()
{
  return 0;//CorrVs_L;
}




uint MODBUS::writeSinglReg(uint adr, uint data)
{
  return ILL_ADDR;
  //return 0;
}

uint MODBUS::writeMultReg(uint adr, uint Nreg)
{
  
  return ILL_FUNC;
  
  //return 0;
}

uint MODBUS::writeMaskReg(uint adr, uint mskAND, uint mskOR)
{
  return ILL_VAL;
  //return 0;
}






void MODBUS::SetGamma(bool GammEncryptOn)
{ if(pGOST!=NULL)  {Gamma = GammEncryptOn;}  else  {Gamma = false;} }


void MODBUS::EncryptSetUp(GOST28147 *pG, bool GammEncryptOn)
{ pGOST = pG; SetGamma(GammEncryptOn); }


void MODBUS::XORask(uint indx)
{ char gam[8]; uint *pA, *pB, ui;
  pA = (uint *)&gam;  pB = (uint *)&gam[4];
  
  while(1)
   {
     (*pGOST).TACTgen(pB,pA);
     for(ui=0; ui<8; ++ui) 
       { if(!(*pUx).XORBufOut(indx,gam[ui])) return; (*pUx).next(&indx); }
    }
  
}


//
bool MODBUS::findID(void)
{
  while(InBgn!=InEnd)
   { 
     queryID = (*pUx).RdBufIn(InBgn);
     if(queryID==myID) {posa = COMask; return true;}
     if(queryID==objectID)  {posa = COMansw; return true;}
     (*pUx).next(&InBgn);
    }
  return false;
}
/*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
//
uint MODBUS::readShort(void)
{ uint data;
  (*pUx).next(&InBgn); data = (uint)(*pUx).RdBufIn(InBgn)<<8;
  (*pUx).next(&InBgn); data += (*pUx).RdBufIn(InBgn);
  return data;
}
/*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/



//
void MODBUS::writeShort(uint data)   { (*pUx).WrBufOut(data>>8);  (*pUx).WrBufOut((char)data); }
/*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/

void MODBUS::writeLong(uint data)
{ 
  (*pUx).WrBufOut((char)data);        (*pUx).WrBufOut((char)(data>>8));
  (*pUx).WrBufOut((char)(data>>16));  (*pUx).WrBufOut(data>>24);
}
/*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/



//
uint MODBUS::RegsToBytes(uint adr,uint nBytes)
{ uint maxBufSize;
  if(nBytes>LastAdr-adr) nBytes = LastAdr-adr;
  if(nBytes>MaxNbytes)   nBytes = MaxNbytes;
  maxBufSize = (*pUx).GetBufSize()/multiplicity*multiplicity - 6;
  if(nBytes>maxBufSize)   nBytes = maxBufSize;
  return nBytes; 
}
/*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/

/*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/